package net.sudot.chess.business.wechat.config;

import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import net.sudot.commons.lock.RedisLock;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * 微信Token存储Redis实现
 *
 * @author tangjialin on 2018-03-14.
 */
public class WechatInRedisConfigStorage extends WxMpInMemoryConfigStorage {
    private final static String ACCESS_TOKEN_KEY = "wechat:access:token:";
    private final static String JSAPI_TICKET_KEY = "wechat:jsapi:ticket:";
    private final static String CARDAPI_TICKET_KEY = "wechat:cardapi:ticket:";

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    private String accessTokenKey;
    private String jsapiTicketKey;
    private String cardapiTicketKey;

    /**
     * 每个公众号生成独有的存储key
     *
     * @param appId
     */
    @Override
    public void setAppId(String appId) {
        super.setAppId(appId);
        this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId);
        this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId);
        this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId);
    }

    @Override
    public String getAccessToken() {
        return redisTemplate.opsForValue().get(accessTokenKey);
    }

    @Override
    public boolean isAccessTokenExpired() {
        return redisTemplate.getExpire(accessTokenKey) < 2L;
    }

    @Override
    public void updateAccessToken(String accessToken, int expiresInSeconds) {
        Lock lock = new RedisLock(redisTemplate, ACCESS_TOKEN_KEY, appId, Duration.ofSeconds(10L));
        if (!lock.tryLock()) { return; }
        try {
            redisTemplate.opsForValue().set(accessTokenKey, accessToken, expiresInSeconds - 200, TimeUnit.SECONDS);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void expireAccessToken() {
        redisTemplate.expire(accessTokenKey, 0, TimeUnit.MILLISECONDS);
    }

    @Override
    public String getJsapiTicket() {
        return redisTemplate.opsForValue().get(jsapiTicketKey);
    }

    @Override
    public boolean isJsapiTicketExpired() {
        return redisTemplate.getExpire(jsapiTicketKey) < 2L;
    }

    @Override
    public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
        Lock lock = new RedisLock(redisTemplate, JSAPI_TICKET_KEY, appId, Duration.ofSeconds(10L));
        if (!lock.tryLock()) { return; }
        try {
            redisTemplate.opsForValue().set(jsapiTicketKey, jsapiTicket, expiresInSeconds - 200, TimeUnit.SECONDS);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void expireJsapiTicket() {
        redisTemplate.expire(jsapiTicketKey, 0, TimeUnit.MILLISECONDS);
    }

    @Override
    public String getCardApiTicket() {
        return redisTemplate.opsForValue().get(cardapiTicketKey);
    }

    @Override
    public boolean isCardApiTicketExpired() {
        return redisTemplate.getExpire(cardapiTicketKey) < 2L;
    }

    @Override
    public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
        Lock lock = new RedisLock(redisTemplate, CARDAPI_TICKET_KEY, appId, Duration.ofSeconds(10L));
        if (!lock.tryLock()) { return; }
        try {
            redisTemplate.opsForValue().set(cardapiTicketKey, cardApiTicket, expiresInSeconds - 200, TimeUnit.SECONDS);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void expireCardApiTicket() {
        redisTemplate.expire(cardapiTicketKey, 0, TimeUnit.MILLISECONDS);
    }
}
